module executor.authorize.AuthorizeExecutor;

import msgtrans;
import message.Constants;
import message.MsgDefine;
import google.protobuf;
import hunt.logging;
import std.array;
import std.conv : to;
import hunt.serialization;
import client.GateServerClient;
import client.MsgServerClient;
import service.LogInService;
import hunt.httpclient;
import app.config.CustomConfig;
import config.ConfigurationDefine;
import grpc;
import repository.UserRepository;
import core.stdc.string;
import repository.DeviceTokenRepository;
import std.stdio;

/**
登录相关模块
**/


@TransportServer(LogicServerName)
class AuthorizeExecutor : AbstractExecutor!(AuthorizeExecutor){

     //接收deviceToken接口
     @MessageId(MESSAGE.CMD_SEND_DEVICE_TOKEN)
     void deviceToken(TransportContext ctx, MessageBuffer buffer) {
         auto req = new SendDeviceToken();
         buffer.data.fromProtobuf!SendDeviceToken(req);

         ServerExtend serverExtend;
         memcpy(&serverExtend,buffer.extend.ptr,ServerExtend.sizeof);

         DeviceTokenRepository u = new DeviceTokenRepository;
         if (req.token != null)
            u.putToken(req.token, cast(uint)serverExtend.userId );
            //u.updateDeviceId(req.token,cast(int)serverExtend.userId,req.src);
     }

    //登录接口
    @MessageId(MESSAGE.CMD_AUTHORIZE_REQ)
    void authorize(TransportContext ctx, MessageBuffer buffer) {
        auto req = new AuthenticateREQ();
        buffer.data.fromProtobuf!AuthenticateREQ(req);
        // logInfo("extend!!! %s --- %s ", buffer.extend.userId, buffer.extend.tagId);
        LoginMode mode = req.loginMode;
        auto res = new AuthenticateRES();
        try
        {
            switch(mode)
            {
                case LoginMode.ACCOUNT: //账号登录
                dealAccountLogin(req,res);
                break;
                case LoginMode.MOBILE:    //手机号登录
                dealMobileLogin(req,res);
                break;
                case LoginMode.TOKEN:     //tokend登录
                dealTokenLogin(req,res);
                break;
                default:
                logError("unknown mode %d" , mode);
                break;
            }
        }catch (Exception e)
        {
            logErrorf("authorize error: %s", e.msg);
            res.code = ErrorCode.ERR_DB;
        }

        res.clientId = req.clientId;
        ctx.session().send(new MessageBuffer(MESSAGE.CMD_AUTHORIZE_RES, res.toProtobuf.array));
    }

    void dealMobileLogin(AuthenticateREQ req ,AuthenticateRES res)
    {
        //string token = AuthorizeByMobile(req.appKey, req.mobile, req.code, res);
        //if (token.length != 0)
        //{
        //    getUserInfo(token, req.appKey, res);
        //    if (res.code == ErrorCode.ERR_NONE)
        //    {
        //        res.authorized = true;
        //        message.MsgDefine.User user = LogInService.processLogin(res.user);
        //        res.user = user;
        //    }
        //}
    }

    void dealAccountLogin(AuthenticateREQ req ,AuthenticateRES res)
    {
        //string token = AuthorizeByAccount(req.appKey,req.username,req.password, res);
        //logInfof("token: %s" ,token);
        //if (token.length != 0)
        //{
        //        getUserInfo(token, req.appKey, res);
        //        if (res.code == ErrorCode.ERR_NONE)
        //        {
        //                res.authorized = true;
        //                message.MsgDefine.User user = LogInService.processLogin(res.user);
        //                res.user = user;
        //        }
        //}
    }

    void dealTokenLogin(AuthenticateREQ req ,AuthenticateRES res)
    {
        getUserInfo(req.accessToken, req.appKey, res);    //访问uas服务验证token
        if (res.code == ErrorCode.ERR_NONE)
        {
            logInfof("UAS response user id: %s, mobile: %s", res.user.id, res.user.mobile);
            std.stdio.stdout.flush();
            
            message.MsgDefine.User user = LogInService.processLogin(res.user); //处理登录业务(更新用户信息，第一次登录插入im_user表)
            if (user is null)
            {
                logError("User data init error! uid: " ~ res.user.id);
                std.stdio.stdout.flush();
            }
            res.user = user;
            LogInService.InitOssInfo(res); //获取系统配置信息
        }
        else
        {
            logError("UAS request faild, error_code: " ~ res.code.to!string ~ ", message: " ~ res.message);
            std.stdio.stdout.flush();
        }
    }

    void getUserInfo(string token, string appKey, AuthenticateRES res)
    {
        // TODO:
        // 用户请求需要放在 PassportService 中去
        string[string] headers;
        headers["appkey"] = appKey;
        headers["Authorization"] = token;
        auto response = Http.withHeaders(headers).get(serverConfig.uas);
        logInfo("res: %s", response.content);
        res.code = ErrorCode.ERR_REMOTE_RETURN;

        // 通用的错误处理是可以提取出去到 PassportService 里边去
        if(!response.isOk() || ("code" in response.json && response.json["code"].integer() != 0))
        {
            res.code = cast(ErrorCode)(response.json["code"].integer());
            res.message = response.json["message"].str();
            res.user = null;

            logWarningf("Auth error code : %d, error message: %s", res.code, res.message);

            return;
        }
        
        logInfof("userId: %s" ,response.content);
        if(res.user is null)
        {
            res.user = new User;
        }

        // TODO:
        // response.json["data"] 需要用 toObject!Userinfo 对象进行绑定，处理更不容易出错
        res.user.id = to!string(response.json["data"]["uid"].integer());
        res.user.nickname = response.json["data"]["nickname"].str();
        res.user.avatar = response.json["data"]["avatar"].str();
        res.user.gender = to!string(response.json["data"]["gender"].integer());
        res.user.birthday = to!string(response.json["data"]["birthday"].integer());
        res.user.mobile = response.json["data"]["mobile"].str();
        res.code = cast(ErrorCode)("code" in response.json ? response.json["code"].integer() : 0);
        res.user.username = response.json["data"]["username"].str();
    }

    string AuthorizeByAccount(string appKey ,string username, string password ,AuthenticateRES res)
    {
        string[string] headers;
        headers["appkey"] = appKey;

        auto response = Http.withHeaders(headers).post("http://account.openchat.mobi/login/username/password",["username": username, "password": password]);

        string token;

        if(response.isOk() && response.json["code"].integer() == 0)
        {
            token = response.json["token"].str();
        }

        if(response.isSuccessful())
        {
            res.code = cast(ErrorCode)(response.json["code"].integer());
        }
        else
        {
            res.code = ErrorCode.ERR_REMOTE_RETURN;
        }

        return token;
    }

    string AuthorizeByMobile(string appKey, string mobile, string code, AuthenticateRES res)
    {
        string[string] headers;
        headers["appkey"] = appKey;
        auto response = Http.withHeaders(headers).post("http://account.openchat.mobi/login/mobile/code",
        ["fullmobile": mobile, "code": code]);
        string token;
        if(response.isOk() && response.json["code"].integer() == 0)
        {
            token = response.json["token"].str();
        }
        if (response.isSuccessful())
        {
            res.code = cast(ErrorCode)(response.json["code"].integer());
        }else
        {
            res.code = ErrorCode.ERR_REMOTE_RETURN;
        }
        return token;
    }
}
